﻿namespace OpenSource.TumblrAPI.ApiV2
{
    using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using OpenSource.TumblrAPI.DataObjects;
using OpenSource.TumblrAPI.Interfaces;
using OpenSource.TumblrAPI.Support;

    public class JsonResponseParser : ITumblrParser
    {
        private ILogger log;

        public JsonResponseParser(ILogger logger)
        {
            this.log = logger;
        }

        public DataObjects.TumblrPost[] Parse(string rawResponse)
        {
            JavaScriptSerializer s = new JavaScriptSerializer();
            Dictionary<string, object> deserialized = s.DeserializeObject(rawResponse) as Dictionary<string, object>;
            object[] rawPosts = deserialized["response"] as object[];
            List<OpenSource.TumblrAPI.DataObjects.TumblrPost> posts = new List<DataObjects.TumblrPost>();
            foreach (object post in rawPosts)
            {
                DataObjects.TumblrPost parsedPost = this.ParsePost(post as Dictionary<string, object>);
                posts.Add(parsedPost);
            }

            return posts.ToArray();
        }

        private OpenSource.TumblrAPI.DataObjects.TumblrPost ParsePost(Dictionary<string, object> rawPost)
        {
            DataObjects.TumblrPost post = new DataObjects.TumblrPost();

            foreach (string key in rawPost.Keys)
            {
                switch (key)
                { 
                    case "album":
                        post.Album = Convert.ToString(rawPost[key]);
                        break;

                    case "artist":
                        post.Artist = Convert.ToString(rawPost[key]);
                        break;

                    case "audio_url":
                        post.AudioUrl = Convert.ToString(rawPost[key]);
                        break;

                    case "blog_name":
                        post.BlogName = Convert.ToString(rawPost[key]);
                        break;

                    case "body":
                        post.Body = Convert.ToString(rawPost[key]);
                        break;

                    case "bookmarklet":
                        post.Bookmarklet = Convert.ToBoolean(rawPost[key]);
                        break;

                    case "caption":
                        post.Caption = Convert.ToString(rawPost[key]);
                        break;

                    case "description":
                        post.Description = Convert.ToString(rawPost[key]);
                        break;

                    case "date":
                        post.Date = Convert.ToDateTime(rawPost[key]);
                        break;

                    case "featured_in_tag":
                        post.FeaturedInTag = Convert.ToString(rawPost[key]);
                        break;

                    case "featured_timestamp":
                        post.FeaturedTimestamp = Convert.ToInt64(rawPost[key]);
                        break;

                    case "format":
                        post.Format = this.ParseEnum<PostFormat>(rawPost[key]);
                        break;

                    case "highlighted":
                        post.Highlighted = this.ParseStringArray(rawPost[key]);
                        break;

                    case "html5_capable":
                        post.Html5Capable = Convert.ToBoolean(rawPost[key]);
                        break;

                    case "id":
                        post.Id = Convert.ToInt64(rawPost[key]);
                        break;

                    case "image_permalink":
                        post.ImagePermaLink = Convert.ToString(rawPost[key]);
                        break;

                    case "link_url":
                        post.LinkUrl = Convert.ToString(rawPost[key]);
                        break;

                    case "mobile":
                        post.Mobile = Convert.ToBoolean(rawPost[key]);
                        break;

                    case "note_count":
                        post.NoteCount = Convert.ToInt32(rawPost[key]);
                        break;

                    case "permalink_url":
                        post.PermaLinkUrl = Convert.ToString(rawPost[key]);
                        break;

                    case "photos":
                        post.Photos = this.ParsePhotos(rawPost[key]);
                        break;

                    case "photoset_layout":
                        post.PhotosetLayout = Convert.ToInt32(rawPost[key]);
                        break;

                    case "player":
                        post.Player = Convert.ToString(rawPost[key]);
                        break;

                    case "plays":
                        post.Plays = Convert.ToInt32(rawPost[key]);
                        break;

                    case "post_url":
                        post.PostUrl = Convert.ToString(rawPost[key]);
                        break;

                    case "reblog_key":
                        post.ReblogKey = Convert.ToString(rawPost[key]);
                        break;

                    case "short_url":
                        post.ShortUrl = Convert.ToString(rawPost[key]);
                        break;

                    case "slug":
                        post.Slug = Convert.ToString(rawPost[key]);
                        break;

                    case "source":
                        post.Source = Convert.ToString(rawPost[key]);
                        break;

                    case "source_title":
                        post.SourceTitle = Convert.ToString(rawPost[key]);
                        break;

                    case "source_url":
                        post.SourceUrl = Convert.ToString(rawPost[key]);
                        break;

                    case "state":
                        post.State = this.ParseEnum<PostState>(rawPost[key]);
                        break;

                    case "tags":
                        post.Tags = this.ParseStringArray(rawPost[key]);
                        break;

                    case "text":
                        post.Text = Convert.ToString(rawPost[key]);
                        break;

                    case "title":
                        post.Title = Convert.ToString(rawPost[key]);
                        break;

                    case "thumbnail_url":
                        post.ThumbnailUrl = Convert.ToString(rawPost[key]);
                        break;

                    case "thumbnail_height":
                        post.ThumbnailWidth = Convert.ToInt32(rawPost[key]);
                        break;

                    case "thumbnail_width":
                        post.ThumbnailWidth = Convert.ToInt32(rawPost[key]);
                        break;

                    case "timestamp":
                        post.TimeStamp = Convert.ToInt64(rawPost[key]);
                        break;

                    case "track":
                        post.Track = Convert.ToInt32(rawPost[key]);
                        break;

                    case "track_name":
                        post.TrackName = Convert.ToString(rawPost[key]);
                        break;

                    case "type":
                        post.PostType = this.ParseEnum<PostType>(rawPost[key]);
                        break;

                    case "url":
                        post.PostUrl = Convert.ToString(rawPost[key]);
                        break;

                    case "year":
                        post.Year = Convert.ToInt32(rawPost[key]);
                        break;

                    default:
                        this.log.Debug("201302091153: The key [{0}] was received, but I don't recognize it!", key);
                        break;
                }
            }

            return post;
        }

        private T ParseEnum<T>(object toParse)
        {
            return (T)Enum.Parse(typeof(T), Convert.ToString(toParse), true);
        }

        private TumblrPhoto ParsePhoto(object rawPhoto, string caption, bool original)
        {
            Dictionary<string, object> photoData = rawPhoto as Dictionary<string, object>;
            TumblrPhoto photo = new TumblrPhoto();
            photo.Caption = caption;
            photo.Original = original;
            photo.Location = Convert.ToString(photoData["url"]);
            photo.Width = Convert.ToInt32(photoData["width"]);
            photo.Height = Convert.ToInt32(photoData["height"]);
            return photo;
        }

        private TumblrPhoto[] ParsePhotos(object rawCollectionOfPhotos)
        {
            object[] foo = rawCollectionOfPhotos as object[];
            Dictionary<string, object> bar = foo[0] as Dictionary<string, object>;
            string caption = Convert.ToString(bar["caption"]);
            object[] altSizes = bar["alt_sizes"] as object[];
            object originalSize = bar["original_size"];

            List<TumblrPhoto> result = new List<TumblrPhoto>();
            result.Add(this.ParsePhoto(originalSize, caption, true));
            foreach (object photo in altSizes)
            {
                result.Add(this.ParsePhoto(photo, caption, false));
            }

            return result.ToArray();
        }

        private string[] ParseStringArray(object rawStringArray)
        {
            object[] rawArray = rawStringArray as object[];
            List<string> result = new List<string>();

            foreach (object item in rawArray)
            {
                result.Add(Convert.ToString(item));
            }

            return result.ToArray();
        }
    }
}
